/******************************************************************************
*
*  Copyright (C)  Chen Ming, All right Reserved
*
*  Current Maintainer: Chen Ming.
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Library General Public
*  License as published by the Free Software Foundation; either
*  version 2 of the License, or (at your option) any later version.
*
*  This library is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*  Library General Public License for more details.
*
*  FILE NAME:      DigiEdit.c
*  PROGRAMMER:     ming.c
*  Date of Creation:   2006/08/8
*
*  DESCRIPTION:
*         DigiEdit
*  NOTE:
*
*  FUNCTIONS LIST:
* -----------------------------------------------------------------------------
*
* -----------------------------------------------------------------------------
* 
*  MODIFICATION HISTORY
*     LastModify  2006/10/30
******************************************************************************/
#include "mingui.h"
//---------------------------------------------------------------------------
#define  MaxDigiWidth      8
//---------------------------------------------------------------------------
typedef struct t_DigiEdit
{ int CaretStart,CaretWidth,CaretHeight,CaretTop,CaretLeft,subfocus;
  float value;
  char  DigiWidth,fbitcount,Digit[MaxDigiWidth];
}TDigiEdit;
//---------------------------------------------------------------------------
void DigiEditDataSync(TDigiEdit *edt,BOOL direction)
{ int i,d,dw;
  float fd;
  dw=(edt->fbitcount>0)? edt->DigiWidth-edt->fbitcount-1:edt->DigiWidth;
  if(direction==true) // edt->Digit[]  -->  edt->Value
  { for(i=0,d=0;i<dw;i++)
    { d=d*10+edt->Digit[i]-'0';
    }
    for(i=0,fd=0;i<edt->fbitcount;i++)
    {  fd=fd+edt->Digit[edt->DigiWidth-i-1]-'0';
       fd=fd*(float)0.1;
    }
    edt->value=d+fd;
  }
  else  // edt->Value -->   edt->Digit[]  
  {   d=(int)edt->value;
      fd=edt->value-d;
      for(i=0;i<dw;i++)
      { edt->Digit[dw-i-1]='0'+(d % 10);
        d=d/10;
      }
      if(edt->fbitcount>0)
      { edt->Digit[dw]='.';
        for(i=0;i<edt->fbitcount;i++)
        { fd=fd*10;
          edt->Digit[dw+i+1]='0'+((int)fd % 10);
        }
      }
      edt->Digit[edt->DigiWidth]='\0';
  }
}
//---------------------------------------------------------------------------
void  DigiEdit_Write(HWND hWnd,float value)
{ if(hWnd)
  { TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
    if(edt)
    { edt->value=value;
      DigiEditDataSync(edt,false);
      Invalidate(hWnd);
    }
  }
}
//---------------------------------------------------------------------------
float DigiEdit_Read(HWND hWnd)
{  if(hWnd)
  { TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
    if(edt)
    { DigiEditDataSync(edt,true);
      return edt->value;
    }
  }
  return 0;
}
//---------------------------------------------------------------------------
void DigiEditFormat(HWND obj,TDigiEdit *edt,char *fmt)
{ edt->value=0;
  if(!fmt)
  { edt->DigiWidth =1;
    edt->fbitcount =0;
  }
  else
  { bool Digi=true;
    char ch;
    float fbit;
    int dotcount;

    for(ch=*fmt;ch==32;ch=*++fmt);
    if(*fmt>='0' && *fmt<='9')edt->DigiWidth=*fmt-'0';
    else edt->DigiWidth=0;
  
    for(ch=*++fmt;ch==32;ch=*++fmt);
    if(*fmt>='0' && *fmt<='9')edt->fbitcount=*fmt-'0';
    else edt->fbitcount=0;

    for(ch=*fmt;ch==32;ch=*++fmt);
    for(ch=*fmt,dotcount=0,fbit=(float)0.1;Digi&&ch!=32&&ch!=0;ch=*++fmt)
    {  if(ch>='0' && ch<='9')
       { if(dotcount==0) edt->value=edt->value*10 + ch-'0';
         else if (dotcount==1)
         { edt->value=edt->value + fbit*(ch-'0');
           fbit*=(float)0.1;
         }
       }
       else if(ch=='.') dotcount++;
       else  Digi=false;
    }
  
    if(edt->fbitcount>0)
    edt->DigiWidth += edt->fbitcount+1;

	if(edt->DigiWidth>MaxDigiWidth)edt->DigiWidth=MaxDigiWidth;
  }  
  DigiEditDataSync(edt,false);
}
//---------------------------------------------------------------------------
void DigiEditCreate(HWND hWnd)
{ TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
  int font_width=WNDPTR(hWnd)->Font->eWidth;
  int font_height=WNDPTR(hWnd)->Font->height;
  memset(edt,0,sizeof(TDigiEdit));
  DigiEditFormat(hWnd,edt,(char *)WndExtraData(hWnd));
  edt->CaretWidth=font_width+2;
  edt->CaretHeight=font_height;
  edt->CaretTop = (crHeight(hWnd) - edt->CaretHeight)/2;
  edt->CaretStart =  ( crWidth(hWnd) - edt->DigiWidth*(font_width+1) +1 )/2;
  edt->CaretLeft=edt->CaretStart-1;
  
}
//---------------------------------------------------------------------------
void DigiEdit_Repaint(HWND hWnd)
{   HDC dc=BeginPaint(hWnd);
    int textx;
    TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
    char *pDataText=edt->Digit;

    if(!WndGetAttr(hWnd,WS_FOCUS) || WndGetAttr(hWnd,WS_DISABLED))
    { int digitcount=edt->DigiWidth;
	  while(*pDataText=='0' && *(pDataText+1)!='.' && *(pDataText+1)!='\0')
	  { pDataText++;
	    digitcount--;
	  }
	  textx= (crWidth(hWnd)-digitcount*WNDPTR(hWnd)->Font->eWidth)/2;
	  if(WndGetAttr(hWnd,WS_DISABLED))
	  {  SetColor (dc, CL_DARKGRAY);
	  }
    }
	else
	{ textx=edt->CaretStart;
	  SetColSpace(dc,1);
	}
    
    TextOut(dc,textx,edt->CaretTop,pDataText);
    
	EndPaint(hWnd);
 
}
//---------------------------------------------------------------------------
void DigiEditChangeSubFocus(HWND hWnd,BOOL direction)
{  TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
   if(direction)
   { edt->subfocus++;
     if(edt->Digit[edt->subfocus]=='.')edt->subfocus++;
   }
   else
   { edt->subfocus--;
     if(edt->Digit[edt->subfocus]=='.')edt->subfocus--;
   }
   edt->CaretLeft=edt->CaretStart+(WNDPTR(hWnd)->Font->eWidth+1)*edt->subfocus-1;
   SetCaretPos(hWnd,edt->CaretLeft,edt->CaretTop);
}
//---------------------------------------------------------------------------
void DigiEditChangeValue(HWND hWnd,BOOL increase)
{  TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
   char textchar[2];
   int digi_width=WNDPTR(hWnd)->Font->eWidth;
   int digi_height=WNDPTR(hWnd)->Font->height;
   int tx=edt->CaretStart+(digi_width+1)*edt->subfocus;
   BOOL hide=HideCaret(hWnd);
   HDC dc=GetDC(hWnd);

   if(increase)
   { if(edt->Digit[edt->subfocus]<'9')edt->Digit[edt->subfocus]++;
     else edt->Digit[edt->subfocus]='0';
   }
   else
   { if(edt->Digit[edt->subfocus]>'0')edt->Digit[edt->subfocus]--;
     else edt->Digit[edt->subfocus]='9';
   }

   textchar[0]=edt->Digit[edt->subfocus];
   textchar[1]='\0';
 
   
   GroupOn(dc);
   EraseBackground(dc,tx,edt->CaretTop,digi_width,digi_height);
   TextOut(dc,tx,edt->CaretTop,textchar);
   GroupOff(dc,tx,edt->CaretTop,digi_width,digi_height);
   ReleaseDC(dc);

   if(hide)ShowCaret(hWnd);
   CMD_NotifyParent(hWnd,CM_CHANGED); 
}
//---------------------------------------------------------------------------
void DigiEditGetChar(HWND hWnd,char keyvalue)
{  TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
   char textchar[2];
   int digi_width=WNDPTR(hWnd)->Font->eWidth;
   int digi_height=WNDPTR(hWnd)->Font->height;
   int tx=edt->CaretStart+(digi_width+1)*edt->subfocus;
   BOOL hide=HideCaret(hWnd);
   HDC dc=GetDC(hWnd);
   
   edt->Digit[edt->subfocus]=keyvalue;

   textchar[0]=keyvalue;
   textchar[1]='\0';

   GroupOn(dc);
   EraseBackground(dc,tx,edt->CaretTop,digi_width,digi_height);
   TextOut(dc,tx,edt->CaretTop,textchar);
   GroupOff(dc,tx,edt->CaretTop,digi_width,digi_height);
   
   ReleaseDC(dc);
   if(hide)ShowCaret(hWnd);
   CMD_NotifyParent(hWnd,CM_CHANGED); 
}
//---------------------------------------------------------------------------
static HRESULT CALLBACK DigiEditProc(HWND hWnd,UINT Message,WPARAM WParam,LPARAM LParam)
{ switch(Message)
  {   
     case WM_KEYDOWN:
          { TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
            switch(WParam)
            {  case VK_UP:    
                       DigiEditChangeValue(hWnd,false);
                    return 0;
               case VK_DOWN:
                       DigiEditChangeValue(hWnd,true);
                    return 0;
               case VK_RIGHT:
                       if(edt->subfocus<edt->DigiWidth-1)
                       { DigiEditChangeSubFocus(hWnd,true);
		                 return 0;
                       } else break; /*DefWindowProc() Will deal focus change*/
               case VK_LEFT:
                       if(edt->subfocus>0)
                       { DigiEditChangeSubFocus(hWnd,false);
		                 return 0;
                       } else break;/*DefWindowProc() Will deal focus change*/
            }
          }
          break;

     case WM_CHAR:
		  {  if(WParam>='0' && WParam<='9')
	       	 { TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
		        if(edt->Digit[edt->subfocus]!=(char)WParam)
		     	{  DigiEditGetChar(hWnd,(char)WParam);
		           if(edt->subfocus<edt->DigiWidth-1)
		           { DigiEditChangeSubFocus(hWnd,true);
				   }
				}
		     }
		  }	  


	 case WM_VSCROLL:
            DigiEditChangeValue(hWnd,((int)LParam>0));
  		  return 0;	

	case WM_LBUTTONDOWN:
		  { TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
		    int xpos=LOWORD(LParam),ypos=HIWORD(LParam);
			if(PointInRect(xpos, ypos, &WNDPTR(hWnd)->ClientRect))
			{  int newedtpos=( xpos-WNDPTR(hWnd)->ClientRect.left - edt->CaretStart ) / (WNDPTR(hWnd)->Font->eWidth+1);
               if(newedtpos<0)newedtpos=0;
               else if(newedtpos>=edt->DigiWidth)newedtpos=edt->DigiWidth-1;
        	   if( newedtpos != edt->subfocus && edt->Digit[newedtpos]!='.')
               { edt->subfocus=newedtpos;
			     edt->CaretLeft=edt->CaretStart+(WNDPTR(hWnd)->Font->eWidth+1)*edt->subfocus-1;
			     SetCaretPos(hWnd,edt->CaretLeft,edt->CaretTop);
			   }
			}	
		  }
		  break;
 
     case WM_CREATE:
            DigiEditCreate(hWnd);
          return 0;
   
	 case WM_PAINT:
		    DigiEdit_Repaint(hWnd);
		  return 0;

     case WM_ENABLE:  
	        Invalidate(hWnd);
	      return 0;

     case WM_SETFOCUS:
		  { TDigiEdit *edt=(TDigiEdit *)WndClsBuf(hWnd);
            CreateCaret (hWnd,  edt->CaretWidth, edt->CaretHeight);
            SetCaretPos (hWnd,edt->CaretLeft, edt->CaretTop);
		    Invalidate(hWnd);
          }
		  return 0;

     case WM_KILLFOCUS:
		    DestroyCaret(hWnd);
		    Invalidate(hWnd);
		  return 0;

  }
  return DefWindowProc(hWnd,Message,WParam,LParam);
}
//---------------------------------------------------------------------------
void CM_RegisterDigiEdit(void)
{  TWNDCLASS wc;
   memset(&wc,0,sizeof(wc));
   wc.dwStyle=WS_BORDER_LOWERED;
   wc.clForeground=CL_WINDOWTEXT;
   wc.clBackground=CL_WHITE;
   wc.cbWndExtra=sizeof(TDigiEdit);
   wc.lpfnWndProc=DigiEditProc;
   wc.lpszClassName="DigiEdit";
   RegisterClass(&wc);
}
//---------------------------------------------------------------------------
